bl_info = {
    "name": "XPR format",
    "author": "Thomas Larsson",
    "location": "File > Import > Import XPR (.xpr)",
    "description": "xpr import.(vertex buffers)",
    "category": "Import-Export"}
 
import bpy
from bpy.props import *
from bpy_extras.io_utils import ExportHelper, ImportHelper
#----------------------------------------------------------
import bpy, os
import struct
import chunk
 
def import_xpr(filepath):
    name = os.path.basename(filepath)
    realpath = os.path.realpath(os.path.expanduser(filepath))
    file = open(realpath, 'rb')    # Universal read
    print('Importing %s' % realpath)
    
    skBones = []
    highBones = []
  #try to open cat file
    skeletonPath = os.path.dirname(filepath) + "\\\\skeletons\\" + name[0] + name[1] + name[2] + ".doau"
    if os.path.lexists(skeletonPath):
        print("skeleton found")
        catpath = realpath.replace('.xpr','.cat')
        if os.path.exists(catpath):
            print("cat found")
            with open(skeletonPath, 'rb') as f:
                temp_read = f.read()
                f.seek(0)
                for i in range(0, len(temp_read), 0x10):
                    skBones.append(struct.unpack("<ffff", f.read(16)))
            print("the skeleton has %d bones = {"% len(skBones))
            for i in range(len(skBones)): print("bone_%d  = \t%f, \t%f, \t%f, \t%f"% (i, skBones[i][0], skBones[i][1], skBones[i][2], skBones[i][3]))
            print("}")
            with open(catpath, 'rb') as f:
                temp = struct.unpack("<L", f.read(4))[0]
                if temp == 0x20:
                    f.seek(28)#go to high poly
                    temp_offset = struct.unpack("<L", f.read(4))[0]
                    f.seek(temp_offset + 0x14)
                    while True:
                        highBones.append(struct.unpack("<BBB", f.read(3)))#B unsigned char
                        if highBones[len(highBones) - 1][0] == 0:
                            highBones.pop()
                            break
                    for i in range(len(highBones)): print("id_%d, bone_%x, OBJ_%d"% (highBones[i][0], highBones[i][1], highBones[i][2]))
                    print("%d high bones"% len(highBones))

                    f.seek(16)#go to joints
                    joints_offset = struct.unpack("<L", f.read(4))[0]
                    f.seek(joints_offset)
                    joints = []
                    joint = struct.unpack("<L", f.read(4))[0]
                    while joint != 0:
                        joints.append(joint)
                        joint = struct.unpack("<L", f.read(4))[0]
                    for i in range(len(joints)):
                        f.seek(joints[i] + joints_offset + 8)
                        jointObj, jointBone = struct.unpack("<BB", f.read(2))
                        highBones.append((3, jointBone, jointObj))
                    print("joints %d"% len(joints))
                else:print("wrong cat header")
        else:print("cat not found")
    else:print("skeleton not found. skeleton folder should be in the same folder with xpr and cat : %s"%skeletonPath)

    #return

    bonesHierarchy = []
    bonesHierarchy.append((2, -1))
    bonesHierarchy.append((0,2))
    bonesHierarchy.append((-1, -1)) #in a python list you can't store a list with size = 0, or size = 1 :((
    bonesHierarchy.append((7,6,2))
    bonesHierarchy.append((8,0,2))
    bonesHierarchy.append((4,8,0,2))
    bonesHierarchy.append((2, -1))
    bonesHierarchy.append((6,2))
    bonesHierarchy.append((0,2))
    bonesHierarchy.append((0xd,0xc,2))
    bonesHierarchy.append((0xe,0,2))
    bonesHierarchy.append((0xa,0xe,0,2))
    bonesHierarchy.append((2, -1))
    bonesHierarchy.append((0xc,2))
    bonesHierarchy.append((0,2))
    
    try:
        dwXprMagic, dwXPRSize, dwHeaderSize, dwChunkID = struct.unpack("<4sLLL", file.read(16))
    except:
        print("Error parsing file header!")
        file.close()
        return
        
    # Handle XPR
    if dwXprMagic == b'XPR0':#is "xpr"
    		if dwChunkID == 0x80000000:
    		    print("mdl ID")#is first chunk a mdl one
    		    dwMDLSize, dwMDLMagic, dwNumObj, dwNumTxt, dwUnk0, dwNumIVBuf = struct.unpack("<1L4sLLLL", file.read(24))
    		    if dwMDLMagic == b'MDL\0':#is magic "mdl"
    		        print("mdl magic. objects %d"% dwNumObj)
    		        objects = []
    		        for object in range(dwNumObj): objects.append(struct.unpack("<1L", file.read(4))[0])
    # Handle OBJ
    		        for object in range(len(objects)):
    		            file.seek(objects[object])
    		            dwOBJMagic = struct.unpack("<4s", file.read(4))[0]
    		            if dwOBJMagic == b'OBJ\0': 
    		                #print("%x obj magic"% (objects[object]))
    		                verts = []
    		                faces = []
    		                indices = []
    		                normals = []
    		                diffuse = []
    		                uv = []
    		              #load first vertex buffer
    		                file.seek(28, 1)
    		                dwNumVertices, dwVBufOffset, dwNumIndices, dwIBufOffset = struct.unpack("<LLLL", file.read(16))
    		                buffer = 0
    		              #if first vertex buffer not found load the second one
    		                if dwNumVertices == 0:
    		                    dwNumVertices, dwVBufOffset, dwNumIndices, dwIBufOffset = struct.unpack("<LLLL", file.read(16))
    		                    buffer = 1
    		              #go to buffer offset and read the fvf
    		                file.seek(dwIBufOffset)
    		                for i in range(dwNumIndices): indices.append(struct.unpack("<1H", file.read(2))[0])#H - usigned short
    		                for i in range(dwNumIndices - 2): faces.append((indices[i], indices[i + 1], indices[i + 2]))
    		                file.seek(dwVBufOffset)
    		                scale = 3
    		                for v in range(dwNumVertices):
    		                    vx, vy, vz = struct.unpack("<fff", file.read(12))
    		                    #verts.append( (scale*vx, -scale*vz, scale*vy) )
    		                    verts.append( (vx, vy, vz) )
    		                    if buffer == 0:
    		                        normals.append(struct.unpack("<3f", file.read(12)))
    		                    else:
    		                        diffuse.append(struct.unpack("<f", file.read(4))[0])
    		                    uv.append(struct.unpack("<2f", file.read(8)))
    		              #create object from verts and faces
    		                name = "vtf%d"% (object + 100)
    		                me = bpy.data.meshes.new(name)
    		                me.from_pydata(verts, [], faces)
    		                me.update()
    		              #add new obj to scene
    		                scn = bpy.context.scene
    		                ob = bpy.data.objects.new(name, me)
    		                scn.objects.link(ob)
    		                scn.objects.active = ob
    		                
    		                isHBone = False
    		                #print("object %x"% object)
    		                for i in range(len(highBones)):
    		                    if object == highBones[i][2]:
    		                        bn = highBones[i][1]
    		                        if bn < len(bonesHierarchy):
    		                            isHBone = True
    		                            newx = skBones[bn][0]
    		                            newy = skBones[bn][1]
    		                            newz = skBones[bn][2]
    		                            print("=====%d"% len(bonesHierarchy[bn]))
    		                            for j in range(len(bonesHierarchy[bn])):
    		                                print("+ %x"% bonesHierarchy[bn][j])
    		                                if bonesHierarchy[bn][j] == -1:
    		                                    break
    		                                else:
    		                                    newx += skBones[bonesHierarchy[bn][j]][0]
    		                                    newy += skBones[bonesHierarchy[bn][j]][1]
    		                                    newz += skBones[bonesHierarchy[bn][j]][2]
    		                            ob.location = [newx, newy, newz]
    		                            break
    		                if isHBone == False: ob.location = [2,0,0]
    		                
    		                #go to edit mode and fix the mesh
    		                bpy.ops.object.mode_set(mode='EDIT')
    		                bpy.ops.mesh.select_all(action='SELECT')
    		                bpy.ops.mesh.normals_make_consistent(inside=False)
    		                bpy.ops.object.editmode_toggle()
    		                
    		        
    		    else:
    		        print("not mdl magic")
    		else: print("first chunk is not mdl chunk %x " % dwChunkID)
    else:
        print("No XPR0 found! %s" % dwXprMagic)
        file.close()
        return

    file.close()
 
    return

class IMPORT_OT_xpr(bpy.types.Operator, ImportHelper):
    bl_idname= "import_scene.xpr"
    bl_description = 'Import from XPR vBuffers (.xpr)'
    bl_label = "Import XPR"
    filename_ext = ".xpr"
    filter_glob = StringProperty(default="*.xpr", options={'HIDDEN'})
 
    filepath= StringProperty(name="File Path", description="Filepath used for importing the XPR file", maxlen=1024, default="")
 
    def execute(self, context): 
        import_xpr(self.properties.filepath)
        return {'FINISHED'}
 
    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}
        

def menu_func(self, context):
    self.layout.operator(IMPORT_OT_xpr.bl_idname, text="XPR vBuffers (.xpr)")

def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file_import.append(menu_func)

def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_file_import.remove(menu_func)

if __name__ == "__main__":
    register()
